home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 013 / rx50.arc / RX50DRVR.ASM < prev    next >
Encoding:
Assembly Source File  |  1986-09-10  |  19.3 KB  |  646 lines

  1.     page    59,120
  2.     title    RX50DRVR -- RX50 Diskette Driver for IBM PC-AT
  3. ;-----------------------------------------------------------------------;
  4. ;                                    ;
  5. ;           RX50DRVR -- RX50 Diskette Driver for IBM PC-AT        ;
  6. ;                                    ;
  7. ;-----------------------------------------------------------------------;
  8. VERSION  equ  05                    ;   08-Dec-84  15:10
  9.  
  10. ;    Copyright (c) 1984 by    Robert F. Morse
  11. ;                17 Bowdoin Street
  12. ;                Cambridge, MA  02138
  13. ;
  14. ; This is an MS-DOS loadable block device driver to support reading and
  15. ; writing DEC RX50 diskettes in the high capacity diskette drive of an
  16. ; IBM PC-AT.  It uses the drive which is known to the normal PC-DOS as
  17. ; drive A: but designates it by the letter assigned when this driver is
  18. ; loaded.  Needless to say, attempting to use both letters at the same
  19. ; time will lead to unpredictable results.
  20.  
  21.     .286C            ;enable 186/286 instructions
  22.  
  23. NUNITS        equ  1        ;number of units supported by this driver
  24. PHYS_DRIVE_0    equ  00h    ;drive number for the HC drive A:
  25. PHYS_BLKSIZE    equ  512    ;blocks always 512 bytes
  26.  
  27. DOSRUPT    equ  21h
  28.  
  29. CR    equ  0Dh
  30. LF    equ  0Ah
  31. ;---------------------------------------------------------------
  32. ;                   IBM ROM BIOS Definitions
  33. ;---------------------------------------------------------------
  34.  
  35. DKOP_RUPT    equ  013h    ;interrupt to call ROM BIOS
  36. DKOP_RESET    equ     000h    ;  reset controller
  37. DKOP_STATUS    equ     001h    ;  read status from last operation
  38. DKOP_READ    equ     002h    ;  read sectors
  39. DKOP_WRITE    equ    003h    ;  write sectors
  40. DKOP_VERIFY    equ    004h    ;  verify sectors
  41. DKOP_CHANGE    equ    016h    ;  test changed status
  42. DKOP_SETTYPE    equ    017h    ;  set media type in drive
  43.  
  44. DKST_TIMEOUT    equ    080h    ;drive not ready
  45. DKST_BADSEEK    equ    040h    ;seek failed
  46. DKST_BADNEC    equ    020h    ;NEC controller failed
  47. DKST_BADCRC    equ    010h    ;read CRC error
  48. DKST_BADDMA    equ    009h    ;attempt to DMA over 64K boundary
  49. DKST_OVERRUN    equ    008h    ;DMA overrun
  50. DKST_CHANGED    equ    006h    ;media changed
  51. DKST_RNF    equ    004h    ;sector not found
  52. DKST_WRPROT    equ    003h    ;write-protected diskette
  53. DKST_ADRMARK    equ    002h    ;address mark not found
  54. DKST_BADCMD    equ    001h    ;invalid command
  55.  
  56.  
  57. BIOS_DATA_SEG  equ  0040h
  58.  
  59. BIOSDATA  segment at BIOS_DATA_SEG    ;BIOS data segment--
  60.  
  61.         org 0090h
  62. bios_dsk_state  db  ?        ;drive 0 media state
  63.  
  64. BIOS_DSK_360K   equ  074h    ;  360kb media established
  65. BIOS_DSK_RX50   equ  054h    ;  RX50 media established in drive 
  66.                 ;    (same as 360kb except single steps
  67.                 ;     for 96 tpi media)
  68. BIOSDATA  ends
  69. ;---------------------------------------------------------------
  70. ;                I/O Request Packet Definition
  71. ;---------------------------------------------------------------
  72.  
  73. iop_struc  struc    ;I/O request packet
  74.   iop_len    db ?    ;  packet length
  75.   iop_unit    db ?    ;  block device unit number
  76.   iop_cmd    db ?    ;  command code, 0..IOP_CMD_MAX
  77.   iop_status    dw ?    ;  status word, see IOPST... tags
  78.         dd ?    ;    future queue link 1
  79.         dd ?    ;    future queue line 2
  80.  
  81.   iop_media    db ?    ;  media descriptor (or read-ahead byte)
  82.   iop_bufoff    dw ?    ;  buffer pointer offset
  83.   iop_bufseg    dw ?    ;    and segment
  84.   iop_count    dw ?    ;  byte/sector count
  85.   iop_block    dw ?    ;  starting block number
  86.   iop_1stdrv    db ?    ;  number of first block drive
  87. iop_struc  ends
  88.  
  89.   iop_nextchar    equ byte  ptr iop_media     ;next available input byte
  90.   iop_nunits    equ byte  ptr iop_media        ;number of units
  91.   iop_bufptr    equ dword ptr iop_bufoff    ;buffer pointer
  92.   iop_return    equ byte  ptr iop_bufoff    ;disk-changed return code
  93.   iop_ckvoloff    equ word  ptr iop_bufoff+1  ;pointer to
  94.   iop_ckvolseg    equ word  ptr iop_bufoff+3  ;   volume name for MEDIACHK
  95.   iop_bpboff    equ word  ptr iop_count     ;pointer to
  96.   iop_bpbseg    equ word  ptr iop_count+2   ;   BPB or BPB list
  97.   iop_endoff    equ word  ptr iop_bufoff    ;pointer to end of
  98.   iop_endseg    equ word  ptr iop_bufoff+2  ;   resident part of driver
  99.   iop_rwvoloff    equ word  ptr iop_block+2   ;pointer to
  100.   iop_rwvolseg    equ word  ptr iop_block+4   ;  volume name for READ/WRITE
  101.  
  102.  
  103. IOP_CMD_MAX    equ 15    ;highest valid command number
  104.  
  105.  
  106. IOPST_BUSY    equ 0200h    ;"busy" status
  107. IOPST_DONE    equ 0100h    ;"done" status
  108.  
  109. IOPST_ERR    equ 8000h    ;"error" status, in combination with--
  110. IOPST_WRPROT    equ 0000h    ;  write-protect
  111. IOPST_BADUNIT    equ 0001h    ;  invalid unit number
  112. IOPST_NOTRDY    equ 0002h    ;  unit not ready
  113. IOPST_BADCMD    equ 0003h    ;  invalid command
  114. IOPST_CRC    equ 0004h    ;  CRC error
  115. IOPST_BADIOP    equ 0005h    ;  bad IOP length
  116. IOPST_SEEK    equ 0006h    ;  seek error
  117. IOPST_UNKMEDIA    equ 0007h    ;  unknown media
  118. IOPST_RNF    equ 0008h    ;  sector not found
  119. IOPST_NOPAPER    equ 0009h    ;  printer out of paper
  120. IOPST_WRFAULT    equ 000Ah    ;  write fault
  121. IOPST_RDFAULT    equ 000Bh    ;  read fault
  122. IOPST_IOERR    equ 000Ch    ;  general I/O failure
  123. IOPST_BADCHNG    equ 000Fh    ;  invalid diskette change
  124. ;---------------------------------------------------------------
  125. ;               Bios Parameter Block Definition
  126. ;---------------------------------------------------------------
  127.  
  128. bpb_struc  struc
  129.   bpb_sectsiz    dw ?    ;  sector size, in bytes
  130.   bpb_sectalu    db ?    ;  sectors per allocation unit
  131.   bpb_reserved    dw ?    ;  number of reserved sectors before 1st FAT
  132.   bpb_numfats    db ?    ;  number of FAT's
  133.   bpb_dirents    dw ?    ;  number of root directory entries
  134.   bpb_totsects    dw ?    ;  total number of sectors on disk
  135.   bpb_media    db ?    ;  media descriptor byte
  136.   bpb_fatsects    dw ?    ;  number of sectors in a FAT
  137.             ;  additional fields to describe media:
  138.   bpb_sect_trk    dw ?    ;    sectors per track
  139.   bpb_head_cyl    dw ?    ;    heads per cylinder
  140.   bpb_hidden    dw ?    ;    number of "hiden" sectors
  141. bpb_struc  ends
  142. ;=======================================================================;
  143. ;                  Permanently Resident Code & Data            ;
  144. ;=======================================================================;
  145.  
  146. DRVRSEG    segment word
  147.  
  148.  
  149. ;-------- I/O Device Header Block --------
  150. ;
  151. ;This is at the first byte of the driver's code image.
  152.  
  153.     BLKDEV    equ  0000h    ;block device
  154.     NONIBM    equ  2000h    ;non-IBM placement of FAT
  155.     REMOVE    equ  0800h    ;has removable media
  156.  
  157. header_rx50  label word
  158.     dd    -1
  159.     dw    BLKDEV+NONIBM+REMOVE
  160.     dw    offset strategy
  161.     dw    offset service
  162.     db    NUNITS, 0,0,0,0,0,0,0
  163.  
  164. ;-------- Bios Parameter Blocks --------
  165.  
  166. init_bpblist  dw  NUNITS dup (offset bpb_rx50)
  167. bpb_rx50  bpb_struc  <512, 1, 20, 2, 96, 800, 0FAh, 3, 10, 1, 0>
  168. ;-------- Working Storage --------
  169.  
  170.         even
  171. io_packet_ptr    dd    ?    ;save cell for IOP pointer
  172. drive_letter    db    'A'    ;letter for first drive supported
  173. vol_name    db    'RX50DISK',0
  174. bpb_pointer    dw    0    ;pointer to currently valid BPB
  175. open_count    dw    0    ;count of open files on device
  176.  
  177.                 ;items for sector transfer loop:
  178. xx_oper        db    ?    ;  operation code
  179. xx_count    dw    ?    ;  block counter
  180. xx_block    dw    ?    ;  block number
  181. xx_buf        dd    ?    ;  buffer pointer:
  182. xx_offset equ word ptr xx_buf    ;    offset
  183. xx_seg    equ word ptr xx_buf+2    ;      and segment
  184. xx_status    db    ?    ;  diskette status code
  185. xx_retries    db    ?    ;  error retry counter
  186.  
  187.  
  188. ;---------------------------------------------------------------
  189. ;  IO_STRATEGY:  strategy routine
  190. ;---------------------------------------------------------------
  191. ;
  192. ;Simple strategy routine which merely saves the I/O packet pointer
  193. ;passed in ES:BX and returns.
  194.  
  195.  
  196.  
  197.       assume  cs:DRVRSEG, ds:nothing
  198. strategy  proc far
  199.     mov    word ptr cs:io_packet_ptr, bx
  200.     mov    word ptr cs:io_packet_ptr+2, es
  201.     ret
  202. strategy  endp
  203. ;---------------------------------------------------------------
  204. ;  IO_SERVICE:  I/O request service routine
  205. ;---------------------------------------------------------------
  206. ;
  207. ;Entry point to command dispatcher for all service requests.  Validates
  208. ;the command and invokes the command execution routine with ES:DI
  209. ;pointing to the I/O packet.
  210.  
  211.      assume  cs:DRVRSEG, ds:nothing, es:nothing
  212. service    proc far
  213.     pusha                ;save caller's registers
  214.     push    ds
  215.     push    es
  216.     cld                ;be sure of direction
  217.  
  218.     mov    ax, cs            ;set up local data segment
  219.     mov    ds, ax
  220.     assume    ds:DRVRSEG
  221.     les    di, io_packet_ptr      ;set ES:DI to I/O packet
  222.  
  223.     mov    al, es:iop_cmd[di]    ;load command code from IOP
  224.     cmp    al, IOP_CMD_MAX        ;  and test its value
  225.     ja    invalid_command
  226.     cbw                ;convert to word index
  227.     add     ax, ax
  228.     xchg    bx, ax            ;put vector index into BX
  229.     xor    ax, ax            ;start with AX=0
  230.     call    drv_cmdtable [bx]    ;call command executor
  231.  
  232. ;Command routines return here with status flags in AX.  Insert the
  233. ;"DONE" bit, store the status in the IOP, and exit from the driver.
  234.  
  235.     assume    cs:DRVRSEG, ds:nothing
  236. epilogue:
  237.     lds     di, io_packet_ptr    ;set DS:DI to IOP
  238.     or    ax, IOPST_DONE        ;insert DONE flag
  239.     mov    ds:iop_status[di], ax    ;  and store status in IOP
  240.  
  241.     pop    es            ;restore caller's regs
  242.     pop    ds
  243.     popa
  244.     ret
  245. service    endp
  246. ;-------- Command dispatch table --------
  247.  
  248.     even
  249. drv_cmdtable  label word
  250.     dw    init        ; 0 -- initialize
  251.     dw    mediachk    ; 1 -- media check
  252.     dw    makebpb        ; 2 -- build BPB
  253.     dw    cmd_dummy    ; 3 -- IOCTL input
  254.     dw    read        ; 4 -- read sectors
  255.     dw    cmd_dummy    ; 5 -- peek at next byte
  256.     dw    cmd_dummy    ; 6 -- test input status
  257.     dw    cmd_dummy    ; 7 -- flush input buffer
  258.     dw    write        ; 8 -- write sectors
  259.     dw    writver        ; 9 -- write and verify sectors
  260.     dw    cmd_dummy    ;10 -- test output status
  261.     dw    cmd_dummy    ;11 -- flush output buffer
  262.     dw    cmd_dummy    ;12 -- IOCTL output
  263.     dw    open        ;13 -- device open
  264.     dw    close        ;14 -- device close
  265.     dw    removable    ;15 -- removable media check
  266.  
  267.  
  268. ;-------- Invalid command --------
  269. ;
  270. ;Load error status and jump to epilogue to return.
  271.  
  272. invalid_command:
  273.     mov    ax, IOPST_ERR + IOPST_BADCMD
  274.     jmp    epilogue
  275.  
  276.  
  277. ;-------- Dummy command --------
  278. ;
  279. ;Perform no operation and return with OK status.
  280.  
  281. cmd_dummy:
  282.     xor    ax, ax            ;no errors
  283.     ret
  284. ;---------------------------------------------------------------
  285. ;  MEDIACHK -- Check for media change
  286. ;---------------------------------------------------------------
  287. ;
  288. ;Test whether the diskette has been changed.  If this is the first
  289. ;use of the unit or if the BPB pointer is 0 (indicating a non-DOS
  290. ;diskette), always reply CHANGED to force a new BPB build.  
  291. ;Otherwise, call the IBM BIOS to test the disk drive's DISKETTE
  292. ;CHANGE line and respond CHANGED or NOCHANGE accordingly.
  293.  
  294. NOCHANGE  equ  1
  295. DONTKNOW  equ  0
  296. CHANGED   equ -1
  297.  
  298.     assume    cs:DRVRSEG, ds:DRVRSEG
  299. mediachk:
  300.     mov    si, bpb_pointer        ;load pointer to BPB
  301.     test    si, si
  302.     jz    mediachk_changed    ;reply CHANGED if non-DOS disk
  303.  
  304. ;Call IBM ROM BIOS to get change status from drive.
  305.  
  306.     mov    dl, PHYS_DRIVE_0    ;load drive number
  307.     mov    ah, DKOP_CHANGE        ;BIOS op-code
  308.     int    DKOP_RUPT
  309.     cmp    ah, 00h
  310.     je    mediachk_nochange
  311. mediachk_changed:
  312.     mov    dl, CHANGED        ;reply "changed"
  313.     xor    ax, ax            ;  with no error code
  314.     mov    open_count, ax        ;zero count of open files
  315.     jmp    short mediachk_result
  316. mediachk_nochange:
  317.     mov    dl, NOCHANGE        ;reply "no change"
  318.     xor    ax, ax            ;  with no error code
  319. mediachk_result:
  320.     les    di, io_packet_ptr    ;get I/O packet pointer
  321.     mov    es:iop_ckvoloff[di], offset vol_name
  322.     mov    es:iop_ckvolseg[di], cs
  323.     mov    es:iop_return[di], dl    ;store change return code
  324.     ret
  325. ;---------------------------------------------------------------
  326. ;  MAKEBPB -- Set up BPB
  327. ;---------------------------------------------------------------
  328. ;
  329. ;Set the ROM BIOS state for the drive to handle RX50 media and
  330. ;return a pointer to the RX50 BPB.
  331.  
  332.     assume    cs:DRVRSEG, ds:DRVRSEG
  333. makebpb:
  334.     mov    open_count, 0        ;zero count of opened files
  335.  
  336.     mov    dl, PHYS_DRIVE_0    ;load drive number
  337.     mov    al, 02h            ;set up 360KB in 1.2m drive
  338.     mov    ah, DKOP_SETTYPE
  339.     int    DKOP_RUPT        ;call BIOS to set up type
  340.     mov    xx_status, ah        ;  and store returned status
  341.  
  342.     test    ah, DKST_TIMEOUT    ;test for drive not ready
  343.     jz    makebpb_01        ;skip if no error
  344.  
  345.     mov    ax, IOPST_ERR+IOPST_NOTRDY
  346.     jmp    short makebpb_ret
  347. makebpb_01:
  348.     mov    ax, BIOS_DATA_SEG    ;change diskette status to
  349.     mov    es, ax            ;  single track stepping for 96 tpi
  350.     mov    es:bios_dsk_state, BIOS_DSK_RX50
  351.  
  352.     mov    si, offset bpb_rx50    ;set up RX50 BPB
  353.     mov    bpb_pointer, si        ;save address of active BPB
  354.  
  355.     les    di, io_packet_ptr    ;point to I/O packet
  356.     mov    al, bpb_media[si]    ;get media descriptor byte
  357.     mov    es:iop_media[di], al    ;  and put into IOP
  358.     mov    es:iop_bpboff[di], si    ;put BPB pointer
  359.     mov    es:iop_bpbseg[di], ds    ;  into IOP
  360.     xor    ax, ax            ;no error
  361. makebpb_ret:
  362.     ret
  363. ;---------------------------------------------------------------
  364. ;  READ and WRITE:  transfer sectors
  365. ;---------------------------------------------------------------
  366.  
  367.     assume    cs:DRVRSEG, ds:DRVRSEG
  368. read:
  369.     mov    al, DKOP_READ        ;set up READ operation
  370.     call    do_readwrite        ;  and do it
  371.     jmp    short rwv_fini
  372.  
  373. write:
  374.     mov    al, DKOP_WRITE        ;set up WRITE operation
  375.     call    do_readwrite        ;  and do it
  376.     jmp    short rwv_fini
  377.  
  378. writver:
  379.     mov    al, DKOP_WRITE        ;set up WRITE operation
  380.     call    do_readwrite        ;  and do it
  381.     test    ax, ax            ;if there is an error
  382.     jnz    rwv_fini        ;  then quit now
  383.  
  384.     les    di, io_packet_ptr    ;reload address of I/O packet
  385.     mov    al, DKOP_VERIFY        ;set up VERIFY operation
  386.     call    do_readwrite        ;  and do it
  387.  
  388. rwv_fini:
  389.     les    di, io_packet_ptr    ;set ES:DI to I/O packet
  390.     mov    dx, xx_count        ;load number of sectors NOT
  391.     sub    es:iop_count[di], dx    ;  transferred and adjust IOP count
  392.  
  393.     ret                ;return with AX = error code
  394. ;Common routine for read, write and verify.
  395. ;
  396. ;Given:    AL = operation code
  397. ;       ES:DI = pointer to IOP, which contains
  398. ;        iop_block = starting block number
  399. ;        iop_bufptr = starting buffer address
  400. ;        iop_count = number of blocks
  401. ;Returns:  AX = IOP error code
  402. ;       xx_count = number of requested blocks NOT transferred
  403.  
  404. do_readwrite:
  405.     mov    es:iop_rwvoloff[di], offset vol_name
  406.     mov    es:iop_rwvolseg[di], cs
  407.  
  408.     mov    xx_oper, al        ;save operation code
  409.  
  410.     mov    ax, es:iop_block[di]    ;set starting block number
  411.     mov    xx_block, ax
  412.     mov    ax, es:iop_count[di]    ;set block count
  413.     mov    xx_count, ax
  414.     test    ax, ax
  415.     jz    dorw_success        ;  quit if 0 sectors to do
  416.  
  417.     mov    ax, es:iop_bufoff[di]    ;set starting buffer offset
  418.     mov    xx_offset, ax        ;  and segment
  419.     mov    ax, es:iop_bufseg[di]
  420.     mov    xx_seg, ax
  421.  
  422. dorw_loop:
  423.     mov    xx_retries, 5        ;set retry counter
  424. dorw_again:
  425.     mov    ax, BIOS_DATA_SEG    ;set diskette status to single
  426.     mov    es, ax            ;  stepping for 96 tpi
  427.     mov    es:bios_dsk_state, BIOS_DSK_RX50
  428.  
  429.     mov    ax, xx_block        ;load block number
  430.     call    makechs_rx50        ;  and convert to CHS
  431.     mov    dl, PHYS_DRIVE_0    ;set drive number
  432.     mov    ah, xx_oper        ;operation code
  433.     mov    al, 1            ;transfer 1 sector
  434.     les    bx, xx_buf        ;set ES:BX to buffer address
  435.     int    DKOP_RUPT        ;invoke ROM BIOS to do it
  436.     mov    xx_status, ah        ;  and save returned status
  437.     test    ah, ah            ;test for error
  438.     jnz    dorw_error        ;  break loop on error
  439.  
  440.     inc    xx_block        ;advance to next block
  441.     add    xx_offset, PHYS_BLKSIZE    ;advance buffer pointer
  442.     dec    xx_count        ;count blocks
  443.     jnz    dorw_loop        ;  and continue until done
  444. dorw_success:
  445.     xor    ax, ax            ;set no-error code
  446.     ret
  447. ;Analyze read/write errors and either make another attempt or
  448. ;set the error code and return.
  449.  
  450. dorw_error:
  451.     mov    al, IOPST_NOTRDY
  452.     test    ah, DKST_TIMEOUT
  453.     jnz    dorw_giveup
  454.  
  455.     mov    al, IOPST_SEEK
  456.     test    ah, DKST_BADSEEK
  457.     jnz    dorw_retry
  458.  
  459.     mov    al, IOPST_IOERR
  460.     test    ah, DKST_BADNEC
  461.     jnz    dorw_retry
  462.  
  463.     cmp    ah, DKST_OVERRUN
  464.     je    dorw_retry
  465.  
  466.     mov    al, IOPST_CRC
  467.     cmp    ah, DKST_BADCRC
  468.     je    dorw_retry
  469.  
  470.     mov    al, IOPST_BADCMD
  471.     cmp    ah, DKST_BADDMA
  472.     je    dorw_giveup
  473.  
  474.     cmp    ah, DKST_BADCMD
  475.     je    dorw_giveup
  476.  
  477.     mov    al, IOPST_BADCHNG
  478.     cmp    ah, DKST_CHANGED
  479.     jne    dorw_nochange
  480.     cmp    open_count, 0
  481.     jg    dorw_giveup        ;error if change with any files open
  482.     jmp    short dorw_reset    ;  else do it again
  483. dorw_nochange:
  484.     mov    al, IOPST_RNF
  485.     cmp    ah, DKST_RNF
  486.     je    dorw_retry
  487.  
  488.     mov    al, IOPST_WRPROT
  489.     cmp    ah, DKST_WRPROT
  490.     je    dorw_giveup
  491.  
  492.     mov    al, IOPST_UNKMEDIA
  493.     cmp    ah, DKST_ADRMARK
  494.     je    dorw_retry
  495.  
  496.     mov    al, IOPST_IOERR
  497.     jmp    short dorw_giveup
  498. dorw_retry:
  499.     dec    xx_retries        ;count retries
  500.     jle    dorw_giveup
  501. dorw_reset:
  502.     mov    ah, DKOP_RESET        ;reset the disk controller
  503.     int    DKOP_RUPT
  504.     jmp    dorw_again        ;  and try again
  505. dorw_giveup:
  506.     mov    ah, high IOPST_ERR    ;complete the driver error return code
  507.     ret
  508. ;-------- MAKECHS_RX50 --------
  509. ;
  510. ;Convert block number to cylinder, head, sector for RX50.  For cylinders
  511. ;2 through 79, the sectors are interleaved 2:1.
  512. ;
  513. ;Given:    AX = block number.
  514. ;Returns:  CH = cylinder,
  515. ;          DH = head,
  516. ;          CL = sector.
  517. ;Destroys: DL, AX.
  518.  
  519. makechs_rx50:
  520.     cwd                ;set up block in DX:AX
  521.     div    secpertrk_rx50        ;AX=track, DX=sector
  522.     xchg    bx, dx            ;get sector into BX
  523.     cmp    al, 2            ;test if cyls 0 or 1
  524.     jb    makechs_rx50_a        ;  skip if so
  525.     mov    bl, interleave_rx50[bx]    ;    else interleave sectors
  526. makechs_rx50_a:
  527.     inc    bx            ;shift to 1-origin sector #
  528.     xchg    dx, bx            ;restore BX
  529.     mov    ch, al            ;CH = cylinder
  530.     mov    dh, 0            ;DH = head
  531.     mov    cl, dl            ;CL = sector
  532.     ret
  533.  
  534. secpertrk_rx50   dw  10            ;sectors per RX50 track
  535.  
  536. interleave_rx50  db  0,2,4,6,8,1,3,5,7,9  ;0-origin sector interleave table
  537. ;---------------------------------------------------------------
  538. ;  OPEN -- Device Open
  539. ;---------------------------------------------------------------
  540. ;
  541. ;Increment the count of opened files on the device.
  542.  
  543.     assume    cs:DRVRSEG, ds:DRVRSEG
  544. open:
  545.     inc    open_count
  546.     ret
  547.  
  548.  
  549. ;---------------------------------------------------------------
  550. ;  CLOSE -- Device Close
  551. ;---------------------------------------------------------------
  552. ;
  553. ;Decrement the count of opened files on the device.
  554.  
  555.     assume    cs:DRVRSEG, ds:DRVRSEG
  556. close:
  557.     cmp    open_count, 0
  558.     jle    close_1
  559.     dec    open_count
  560. close_1:
  561.     ret
  562.  
  563.  
  564. ;---------------------------------------------------------------
  565. ;  REMOVABLE -- Report that Media are Removable
  566. ;---------------------------------------------------------------
  567. ;
  568. ;Return with IOPST_BUSY = 0 to indicate that media can be removed
  569. ;from this device.
  570.  
  571.     assume    cs:DRVRSEG, ds:DRVRSEG
  572. removable:
  573.     ret
  574. ;=======================================================================;
  575. ;                      Initialization  Code & Data            ;
  576. ;=======================================================================;
  577. ;
  578. ;Code and data from here on are discarded after INIT is called.
  579.  
  580.         even
  581. end_permanent_code  label  byte
  582.  
  583.  
  584. init_msg_1    db  CR,LF,'RX50DRVR version '
  585.         db  (VERSION  /  10) + '0'
  586.         db  (VERSION mod 10) + '0'
  587.         db  '             Copyright (c) 1984 by Robert F. Morse'
  588.         db  CR,LF,'         Loaded at '
  589. init_msg_seg    db  '0000'
  590.         db  '0 and refers to drive as '
  591. init_msg_ltr    db  'A:'
  592.         db  CR,LF,'$'
  593. ;---------------------------------------------------------------
  594. ;  INIT -- Driver Initialization
  595. ;---------------------------------------------------------------
  596.  
  597.     assume    cs:DRVRSEG, ds:DRVRSEG
  598. init:
  599.  
  600. ;Put the drive letter and the segment at which the drive has been loaded
  601. ;into the signon message and display it.
  602.  
  603.     mov    al, es:iop_1stdrv[di]    ;get number to designate 1st drive
  604.     add    drive_letter, al    ;  save it
  605.     add    init_msg_ltr, al    ;  put in message
  606.  
  607.     mov    bx, offset init_msg_seg    ;put driver's address into msg
  608.     mov    cx, 4
  609.     mov    dx, cs
  610. init_hex_loop:
  611.     rol    dx, 4            ;convert left digit of DX to 
  612.     mov    al, dl            ;  hex and store at [BX]+
  613.     and    al, 0Fh
  614.     add    al, '0'
  615.     cmp    al, '9'
  616.     jbe    init_hex_loop_1
  617.     add    al, 'A'-'9'-1
  618. init_hex_loop_1:
  619.     mov    [bx], al
  620.     inc    bx
  621.     loop    init_hex_loop        ;do 4 digits
  622.  
  623.     mov    dx, offset init_msg_1    ;display completed msg
  624.     mov    ah, 09h
  625.     int    DOSRUPT
  626.  
  627. ;Fill in IOP with number of units, pointer to list of BPB's, and
  628. ;pointer to end of permanent code.
  629.  
  630.     assume    ds:nothing
  631.     lds    di, io_packet_ptr    ;set DS:DI to I/O packet
  632.  
  633.     mov    ds:iop_nunits[di], NUNITS
  634.  
  635.     mov    ds:iop_bpboff[di], offset init_bpblist
  636.     mov    ds:iop_bpbseg[di], cs
  637.  
  638.     mov    ds:iop_endoff[di], offset end_permanent_code
  639.     mov    ds:iop_endseg[di], cs
  640.  
  641.     xor    ax, ax            ;return no error
  642.     ret
  643.  
  644. DRVRSEG    ends
  645.     end
  646.